Tumor evolution project
Data used
In this notebook, we are using the pbta.tsv file
geenrated by the sample-distribution-analysis module.
Set up
suppressPackageStartupMessages({
library(tidyverse)
library(rstatix)
library(ggpubr)
})
Read in data and process
# Make this reproducible
set.seed(2023)
# Read in tmb file and remove hypermutant samples
tmb <- readr::read_tsv(tmb_file, guess_max = 100000, show_col_types = FALSE) %>%
filter(!tmb >= 10) %>%
dplyr::rename(Kids_First_Biospecimen_ID = Tumor_Sample_Barcode) # change name of the biospecimen to match the one from the histologies files
# Read in pbta file and create df_plot
df_plot <- readr::read_tsv(pbta_file, guess_max = 100000, show_col_types = FALSE) %>%
filter(!(experimental_strategy == "RNA-Seq"),
!(tumor_descriptor == "Unavailable")) %>% # these are 2 samples
left_join(tmb, by = c("Kids_First_Biospecimen_ID", "experimental_strategy")) %>%
select(Kids_First_Participant_ID, Kids_First_Biospecimen_ID, tumor_descriptor,
broad_histology, match_id_DNA, experimental_strategy,
cancer_group, short_histology, tmb, mutation_count, DNA) %>%
dplyr:::mutate(short_histology_sum = ifelse(short_histology == "HGAT", "HGG",
ifelse(short_histology == "LGAT", "LGG",
ifelse(short_histology == "Ependymoma", "Ependymoma",
ifelse(short_histology == "Medulloblastoma", "Medulloblastoma", "Other"))),
log10_tmb = abs(log10(tmb)),
tumor_descriptor = factor(tumor_descriptor),
tumor_descriptor = fct_relevel(tumor_descriptor, c("Diagnosis", "Progressive", "Recurrence", "Deceased", "Second Malignancy", "Unavailable"))) %>%
distinct(match_id_DNA, .keep_all = TRUE) %>% # keep only one bs_sample per genomic assay (WGS/WXS)
filter(!is.na(tmb))
# How many samples per Timepoint?
print(df_plot %>% count(tumor_descriptor))
Error: unexpected symbol in:
"# How many samples per Timepoint?
print"
How many patient samples in the unpaired longitudinal data?
There are 1924 samples in total.
All unpaired samples
We are interested in how TMB changes over the time in all PBTA
samples (unpaired samples).
# Read color palette
palette_df <- readr::read_tsv(palette_file, guess_max = 100000, show_col_types = FALSE) %>%
mutate(tumor_descriptor = color_names)
# Define and order palette
palette <- palette_df$hex_codes
names(palette) <- palette_df$tumor_descriptor
# Define label for plots
Timepoint <- df_plot$tumor_descriptor
# Define ylim
ylim <- max(df_plot$tmb)
print(df_plot %>%
ggplot2::ggplot() +
ggplot2::aes(x = tumor_descriptor,
y = tmb,
color = Timepoint) +
ggplot2::geom_jitter(width = 0.2, alpha = 0.5, size = 1.5) +
# light guiding line representing 0 exposure
ggplot2::geom_hline(yintercept = 0, size = 0.15) +
ggplot2::scale_color_manual(values = palette,
breaks = sort(names(palette))) +
ggplot2::stat_summary(color = "black", size = 0.3) +
ggplot2::labs(x = "Tumor descriptor",
y = "TMB") +
theme_Publication() +
scale_y_continuous(limits = c(0, ylim)) +
theme(axis.text.x = element_text(angle = 90)))

# Save the plot
ggsave(filename = "TMB-unpaired-longitudinal-samples.pdf",
path = plots_dir,
width = 10,
height = 5,
device = "pdf",
useDingbats = FALSE)
All unpaired samples across cancer types
We will use the short_histology column to display TMB
differences across cancer types.
print(df_plot %>%
ggplot2::ggplot() +
ggplot2::aes(x = tumor_descriptor,
y = tmb,
color = Timepoint) +
ggplot2::geom_jitter(width = 0.2, alpha = 0.5, size = 1.5) +
# light guiding line representing 0 exposure
ggplot2::geom_hline(yintercept = 0, size = 0.15) +
ggplot2::scale_color_manual(values = palette,
breaks = sort(names(palette))) +
ggplot2::stat_summary(color = "black", size = 0.3) +
ggplot2::facet_wrap(~short_histology, nrow = 8) +
ggplot2::labs(x = "Tumor descriptor",
y = "TMB") +
theme_Publication() +
theme(axis.text.x = element_text(angle = 90)) +
scale_y_continuous(limits = c(0, ylim)))

# Save the plot
ggsave(filename = "TMB-unpaired-longitudinal-samples-cancer-type.pdf",
path = plots_dir,
width = 25,
height = 20,
device = "pdf",
useDingbats = FALSE)
We observe that majority of samples are High- and Low-grade gliomas
as well as Ependymoma, so we will classify accordingly (versus any other
cancer types).
All unpaired samples across cancer types summarized
# Create col with sample size per cancer type
df_plot_n <- df_plot %>%
dplyr::count(tumor_descriptor) %>%
dplyr::distinct() %>%
dplyr::inner_join(
dplyr::select(palette_df, dplyr::contains("tumor_descriptor"))) %>%
dplyr::select(tumor_descriptor, n) %>%
# Create wrapped with (n=X) factor column for cancer groups
dplyr::mutate(tumor_descriptor_n = glue::glue("{tumor_descriptor} (N={n})")) %>%
dplyr::inner_join(df_plot) %>%
unique() %>%
# reverse order levels to alphabetize when flipping coordinates
mutate(tumor_descriptor_n = fct_rev(tumor_descriptor_n))
Joining with `by = join_by(tumor_descriptor)`Joining with `by = join_by(tumor_descriptor)`
print(df_plot %>%
ggplot2::ggplot() +
ggplot2::aes(x = tumor_descriptor,
y = tmb,
color = Timepoint) +
ggplot2::geom_jitter(width = 0.2, alpha = 0.5, size = 1.5) +
# light guiding line representing 0 exposure
ggplot2::geom_hline(yintercept = 0, size = 0.15) +
ggplot2::scale_color_manual(values = palette,
breaks = sort(names(palette))) +
ggplot2::stat_summary(color = "black", size = 0.3) +
ggplot2::facet_wrap(~short_histology_sum, nrow = 1) +
ggplot2::labs(x = "Tumor descriptor",
y = "TMB") +
theme_Publication() +
theme(axis.text.x = element_text(angle = 90)) +
scale_y_continuous(limits = c(0, ylim)))

# Save the plot
ggsave(filename = "TMB-unpaired-longitudinal-samples-cancer-type-sum.pdf",
path = plots_dir,
width = 12,
height = 6,
device = "pdf",
useDingbats = FALSE)
Summary statistics for Timepoints and cancer types
Considering the inequalities in the sampling effort for each
timepoint, let’s explore whether the sampling size affects the observed
patterns, e.g., indication of Progressive and Recurrence having higer
TMB compared to Diagnosis for High-grade glioma patients.
# Inspect some random rows of the data by groups
set.seed(2023)
df_plot %>%
select(short_histology_sum, tumor_descriptor, tmb, log10_tmb) %>%
sample_n_by(short_histology_sum, tumor_descriptor, tmb, size = 1)
# Compute some summary statistics (mean and sd) by groups:
stat.summary <- df_plot %>%
group_by(tumor_descriptor, short_histology_sum) %>%
get_summary_stats(tmb, type = "mean_sd") %>%
filter(!n <= 2) # remove if total number of values per group is less than 2
stat.summary
# Pairwise comparisons between time points at each group levels
# Paired t-test is used because we have repeated measures by time
stat.test <- df_plot %>%
group_by(short_histology_sum) %>%
pairwise_t_test(log10_tmb ~ tumor_descriptor,
paired = FALSE,
p.adjust.method = "bonferroni")
stat.test
# Add statistical test p-values
stat.test <- stat.test %>% add_xy_position(x = "tumor_descriptor")
# Create bxp
print(ggboxplot(df_plot,
x = "tumor_descriptor",
y = "log10_tmb",
color = "tumor_descriptor",
palette = palette) +
facet_wrap(~short_histology_sum, nrow = 1) +
theme_Publication() +
theme(axis.text.x = element_text(angle = 90)) +
stat_pvalue_manual(stat.test, label = "p.adj.signif",
step.increase = 0.08, hide.ns = TRUE, tip.length = 0))

# Save the plot
ggsave(filename = "TMB-Bxp-stat-test.pdf",
path = plots_dir,
width = 12,
height = 6,
device = "pdf",
useDingbats = FALSE)
# Create jitter plot
print(df_plot %>%
ggplot2::ggplot() +
ggplot2::aes(x = tumor_descriptor,
y = log10_tmb,
color = Timepoint) +
ggplot2::geom_jitter(width = 0.2, alpha = 0.5, size = 1.5) +
# light guiding line representing 0 exposure
ggplot2::geom_hline(yintercept = 0, size = 0.15) +
ggplot2::scale_color_manual(values = palette,
breaks = sort(names(palette))) +
facet_wrap(~short_histology_sum, nrow = 1) +
theme_Publication() +
theme(axis.text.x = element_text(angle = 90)) +
stat_pvalue_manual(stat.test, label = "p.adj.signif",
step.increase = 0.08, hide.ns = TRUE, tip.length = 0))

# Save the plot
ggsave(filename = "TMB-jitter-stat-test.pdf",
path = plots_dir,
width = 12,
height = 6,
device = "pdf",
useDingbats = FALSE)
# This code was inspired by the following:
# HOW TO PERFORM MULTIPLE PAIRED T-TESTS IN R
# https://www.datanovia.com/en/blog/how-to-perform-multiple-paired-t-tests-in-r/
sessionInfo()
R version 4.2.3 (2023-03-15)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Ventura 13.4.1
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] grid stats graphics grDevices utils datasets methods
[8] base
other attached packages:
[1] ggthemes_4.2.4 ggpubr_0.6.0 rstatix_0.7.2 lubridate_1.9.2
[5] forcats_1.0.0 stringr_1.5.0 dplyr_1.1.2 purrr_1.0.1
[9] readr_2.1.4 tidyr_1.3.0 tibble_3.2.1 ggplot2_3.4.2
[13] tidyverse_2.0.0
loaded via a namespace (and not attached):
[1] tidyselect_1.2.0 xfun_0.39 bslib_0.5.0 carData_3.0-5
[5] colorspace_2.1-0 vctrs_0.6.3 generics_0.1.3 htmltools_0.5.5
[9] yaml_2.3.7 utf8_1.2.3 rlang_1.1.1 jquerylib_0.1.4
[13] pillar_1.9.0 glue_1.6.2 withr_2.5.0 bit64_4.0.5
[17] lifecycle_1.0.3 munsell_0.5.0 ggsignif_0.6.4 gtable_0.3.3
[21] ragg_1.2.5 evaluate_0.21 labeling_0.4.2 knitr_1.43
[25] tzdb_0.4.0 fastmap_1.1.1 parallel_4.2.3 fansi_1.0.4
[29] highr_0.10 broom_1.0.5 scales_1.2.1 backports_1.4.1
[33] cachem_1.0.8 vroom_1.6.3 jsonlite_1.8.7 abind_1.4-5
[37] systemfonts_1.0.4 farver_2.1.1 bit_4.0.5 textshaping_0.3.6
[41] hms_1.1.3 digest_0.6.33 stringi_1.7.12 rprojroot_2.0.3
[45] cli_3.6.1 tools_4.2.3 magrittr_2.0.3 sass_0.4.7
[49] crayon_1.5.2 car_3.1-2 pkgconfig_2.0.3 timechange_0.2.0
[53] rmarkdown_2.23 R6_2.5.1 compiler_4.2.3
LS0tCnRpdGxlOiAiVE1CIG9mIHR1bW9ycyBhY3Jvc3MgdW5wYWlyZWQgbG9uZ2l0dWRpbmFsIHNhbXBsZXMgaW4gdGhlIFBCVEEgQ29ob3J0IgphdXRob3I6ICdBbnRvbmlhIENocm9uaSA8Y2hyb25pYUBjaG9wLmVkdT4gYW5kIEpvIEx5bm5lIFJva2l0YSA8cm9raXRhQGNob3AuZWR1PiBmb3IgRDNCJwpkYXRlOiAiMjAyMyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IFRSVUUKICAgIHRvY19mbG9hdDogVFJVRQotLS0KCiMjIyMgVHVtb3IgZXZvbHV0aW9uIHByb2plY3QgCgojIyMgRGF0YSB1c2VkIApJbiB0aGlzIG5vdGVib29rLCB3ZSBhcmUgdXNpbmcgdGhlIGBwYnRhLnRzdmAgZmlsZSBnZWVucmF0ZWQgYnkgdGhlIGBzYW1wbGUtZGlzdHJpYnV0aW9uLWFuYWx5c2lzYCBtb2R1bGUuCgojIFNldCB1cApgYGB7ciBsb2FkLWxpYnJhcnl9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyh7CiAgbGlicmFyeSh0aWR5dmVyc2UpCiAgbGlicmFyeShyc3RhdGl4KQogIGxpYnJhcnkoZ2dwdWJyKQp9KQpgYGAKCiMjIERpcmVjdG9yaWVzIGFuZCBGaWxlIElucHV0cy9PdXRwdXRzCmBgYHtyIHNldC1kaXItYW5kLWZpbGUtbmFtZXN9CiMgRGV0ZWN0IHRoZSAiLmdpdCIgZm9sZGVyIC0tIHRoaXMgd2lsbCBiZSBpbiB0aGUgcHJvamVjdCByb290IGRpcmVjdG9yeQojIFVzZSB0aGlzIGFzIHRoZSByb290IGRpcmVjdG9yeSB0byBlbnN1cmUgcHJvcGVyIHNvdXJjaW5nIG9mIGZ1bmN0aW9ucyAKIyBubyBtYXR0ZXIgd2hlcmUgdGhpcyBpcyBjYWxsZWQgZnJvbQpyb290X2RpciA8LSBycHJvanJvb3Q6OmZpbmRfcm9vdChycHJvanJvb3Q6Omhhc19kaXIoIi5naXQiKSkKYW5hbHlzaXNfZGlyIDwtIGZpbGUucGF0aChyb290X2RpciwgImFuYWx5c2VzIiwgInRtYi12YWYtbG9uZ2l0dWRpbmFsIikKaW5wdXRfZGlyIDwtIGZpbGUucGF0aChhbmFseXNpc19kaXIsICJpbnB1dCIpCmZpbGVzX2RpciA8LSBmaWxlLnBhdGgocm9vdF9kaXIsICJhbmFseXNlcyIsICJzYW1wbGUtZGlzdHJpYnV0aW9uLWFuYWx5c2lzIiwgInJlc3VsdHMiKQoKIyBJbnB1dCBmaWxlcwpwYnRhX2ZpbGUgPC0gZmlsZS5wYXRoKGZpbGVzX2RpciwgInBidGEudHN2IikgIyBmaWxlIGZyb20gYWRkLXNhbXBsZS1kaXN0cmlidXRpb24gbW9kdWxlCnRtYl9maWxlIDwtIGZpbGUucGF0aChpbnB1dF9kaXIsICJzbnYtbXV0YXRpb24tdG1iLWNvZGluZy50c3YiKQpwYWxldHRlX2ZpbGUgPC0gZmlsZS5wYXRoKHJvb3RfZGlyLCAiZmlndXJlcyIsICJwYWxldHRlcyIsICJ0dW1vcl9kZXNjcmlwdG9yX2NvbG9yX3BhbGV0dGUudHN2IikKCiMgRmlsZSBwYXRoIHRvIHBsb3QgZGlyZWN0b3J5CnBsb3RzX2RpciA8LQogIGZpbGUucGF0aChhbmFseXNpc19kaXIsICJwbG90cyIpCmlmICghZGlyLmV4aXN0cyhwbG90c19kaXIpKSB7CiAgZGlyLmNyZWF0ZShwbG90c19kaXIpCn0KCnNvdXJjZShwYXN0ZTAocm9vdF9kaXIsICIvZmlndXJlcy9zY3JpcHRzL3RoZW1lLlIiKSkKYGBgCgojIyBSZWFkIGluIGRhdGEgYW5kIHByb2Nlc3MKYGBge3IgbG9hZC1wcm9jZXNzLWlucHV0c30KIyBNYWtlIHRoaXMgcmVwcm9kdWNpYmxlCnNldC5zZWVkKDIwMjMpCgojIFJlYWQgaW4gdG1iIGZpbGUgYW5kIHJlbW92ZSBoeXBlcm11dGFudCBzYW1wbGVzCnRtYiA8LSByZWFkcjo6cmVhZF90c3YodG1iX2ZpbGUsIGd1ZXNzX21heCA9IDEwMDAwMCwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZmlsdGVyKCF0bWIgPj0gMTApICU+JSAKICBkcGx5cjo6cmVuYW1lKEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQgPSBUdW1vcl9TYW1wbGVfQmFyY29kZSkgIyBjaGFuZ2UgbmFtZSBvZiB0aGUgYmlvc3BlY2ltZW4gdG8gbWF0Y2ggdGhlIG9uZSBmcm9tIHRoZSBoaXN0b2xvZ2llcyBmaWxlcwoKIyBSZWFkIGluIHBidGEgZmlsZSBhbmQgY3JlYXRlIGRmX3Bsb3QKZGZfcGxvdCA8LSByZWFkcjo6cmVhZF90c3YocGJ0YV9maWxlLCBndWVzc19tYXggPSAxMDAwMDAsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGZpbHRlcighKGV4cGVyaW1lbnRhbF9zdHJhdGVneSA9PSAiUk5BLVNlcSIpLAogICAgICAgICAhKHR1bW9yX2Rlc2NyaXB0b3IgPT0gIlVuYXZhaWxhYmxlIikpICU+JSAjIHRoZXNlIGFyZSAyIHNhbXBsZXMKICBsZWZ0X2pvaW4odG1iLCBieSA9IGMoIktpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQiLCAiZXhwZXJpbWVudGFsX3N0cmF0ZWd5IikpICU+JQogIHNlbGVjdChLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lELCBLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lELCB0dW1vcl9kZXNjcmlwdG9yLAogICAgICAgICBicm9hZF9oaXN0b2xvZ3ksIG1hdGNoX2lkX0ROQSwgZXhwZXJpbWVudGFsX3N0cmF0ZWd5LCAKICAgICAgICAgY2FuY2VyX2dyb3VwLCBzaG9ydF9oaXN0b2xvZ3ksIHRtYiwgbXV0YXRpb25fY291bnQsIEROQSkgJT4lCiAgZHBseXI6OjptdXRhdGUoc2hvcnRfaGlzdG9sb2d5X3N1bSA9IGlmZWxzZShzaG9ydF9oaXN0b2xvZ3kgPT0gIkhHQVQiLCAiSEdHIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzaG9ydF9oaXN0b2xvZ3kgPT0gIkxHQVQiLCAiTEdHIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNob3J0X2hpc3RvbG9neSA9PSAiRXBlbmR5bW9tYSIsICJFcGVuZHltb21hIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzaG9ydF9oaXN0b2xvZ3kgPT0gIk1lZHVsbG9ibGFzdG9tYSIsICJNZWR1bGxvYmxhc3RvbWEiLCAiT3RoZXIiKSkpKSwKICAgICAgICAgICAgICAgICBsb2cxMF90bWIgPSBhYnMobG9nMTAodG1iKSksCiAgICAgICAgICAgICAgICAgdHVtb3JfZGVzY3JpcHRvciA9IGZhY3Rvcih0dW1vcl9kZXNjcmlwdG9yKSwKICAgICAgICAgICAgICAgICB0dW1vcl9kZXNjcmlwdG9yID0gZmN0X3JlbGV2ZWwodHVtb3JfZGVzY3JpcHRvciwgYygiRGlhZ25vc2lzIiwgIlByb2dyZXNzaXZlIiwgIlJlY3VycmVuY2UiLCAiRGVjZWFzZWQiLCAiU2Vjb25kIE1hbGlnbmFuY3kiLCAiVW5hdmFpbGFibGUiKSkpICU+JSAKICBkaXN0aW5jdChtYXRjaF9pZF9ETkEsIC5rZWVwX2FsbCA9IFRSVUUpICU+JSAjIGtlZXAgb25seSBvbmUgYnNfc2FtcGxlIHBlciBnZW5vbWljIGFzc2F5IChXR1MvV1hTKQogIGZpbHRlcighaXMubmEodG1iKSkKCiMgSG93IG1hbnkgc2FtcGxlcyBwZXIgVGltZXBvaW50PwpwcmludChkZl9wbG90ICU+JSBjb3VudCh0dW1vcl9kZXNjcmlwdG9yKSkKCiMgSG93IG1hbnkgc2FtcGxlcyBwZXIgY2FuY2VyIHR5cGU/CnByaW50KGRmX3Bsb3QgJT4lIGNvdW50KHNob3J0X2hpc3RvbG9neV9zdW0pKQoKIyBIb3cgbWFueSBzYW1wbGVzIHBlciBUaW1lcG9pbnQgYW5kIGNhbmNlciB0eXBlPwpyZW5hbWUoY291bnQoZGZfcGxvdCwgdHVtb3JfZGVzY3JpcHRvciwgc2hvcnRfaGlzdG9sb2d5X3N1bSksIEZyZXEgPSBuKQoKIyBIb3cgbWFueSBjYXNlcyB3aXRoIHVucGFpcmVkIGxvbmdpdHVkaW5hbCBzYW1wbGVzPwpub19zYW1wbGVzIDwtIGxlbmd0aCh1bmlxdWUoZGZfcGxvdCRLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEKSkKCiMgTGV0J3MgY291bnQgYW5kIHJlbW92ZSBhbnkgdGltZXBvaW50cyB3aXRoIGxlc3MgdGhhbiAyIHNhbXBsZXMgdGhlcmVpbgp0aW1lcG9pbnRfbiA8LSBkZl9wbG90ICU+JSAKICBjb3VudCh0dW1vcl9kZXNjcmlwdG9yKSAlPiUgCiAgZHBseXI6Om11dGF0ZSh0dW1vcl9kZXNjcmlwdG9yX24gPSBnbHVlOjpnbHVlKCJ7dHVtb3JfZGVzY3JpcHRvcn0gKE49e259KSIpKQoKZGZfcGxvdCA8LSBkZl9wbG90ICU+JSAKICBsZWZ0X2pvaW4odGltZXBvaW50X24sIGJ5ID0gYygidHVtb3JfZGVzY3JpcHRvciIpKSAlPiUKICBmaWx0ZXIoIW4gPD0gMikgIyByZW1vdmUgaWYgdG90YWwgbnVtYmVyIG9mIHZhbHVlcyBwZXIgZ3JvdXAgaXMgbGVzcyB0aGFuIDIKYGBgIAoKCiMjIEhvdyBtYW55IHBhdGllbnQgc2FtcGxlcyBpbiB0aGUgdW5wYWlyZWQgbG9uZ2l0dWRpbmFsIGRhdGE/ClRoZXJlIGFyZSBgciBub19zYW1wbGVzYCBzYW1wbGVzIGluIHRvdGFsLgoKIyBBbGwgdW5wYWlyZWQgc2FtcGxlcwpXZSBhcmUgaW50ZXJlc3RlZCBpbiBob3cgVE1CIGNoYW5nZXMgb3ZlciB0aGUgdGltZSBpbiBhbGwgUEJUQSBzYW1wbGVzICh1bnBhaXJlZCBzYW1wbGVzKS4KCmBgYHtyIGRlZmluZS1wYXJhbWV0ZXJzLWZvci1wbG90c30KIyBSZWFkIGNvbG9yIHBhbGV0dGUKcGFsZXR0ZV9kZiA8LSByZWFkcjo6cmVhZF90c3YocGFsZXR0ZV9maWxlLCBndWVzc19tYXggPSAxMDAwMDAsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JSAKICBtdXRhdGUodHVtb3JfZGVzY3JpcHRvciA9IGNvbG9yX25hbWVzKQoKIyBEZWZpbmUgYW5kIG9yZGVyIHBhbGV0dGUKcGFsZXR0ZSA8LSBwYWxldHRlX2RmJGhleF9jb2RlcwpuYW1lcyhwYWxldHRlKSA8LSBwYWxldHRlX2RmJHR1bW9yX2Rlc2NyaXB0b3IKCiMgRGVmaW5lIGxhYmVsIGZvciBwbG90cwpUaW1lcG9pbnQgPC0gZGZfcGxvdCR0dW1vcl9kZXNjcmlwdG9yCgojIERlZmluZSB5bGltCnlsaW0gPC0gbWF4KGRmX3Bsb3QkdG1iKQpgYGAKCmBgYHtyIHBsb3QtdG90YWwsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLmZ1bGx3aWR0aCA9IFRSVUV9CnByaW50KGRmX3Bsb3QgJT4lIAogICAgICAgIGdncGxvdDI6OmdncGxvdCgpICsgCiAgICAgICAgZ2dwbG90Mjo6YWVzKHggPSB0dW1vcl9kZXNjcmlwdG9yLCAKICAgICAgICAgICAgICAgICAgICAgeSA9IHRtYiwKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBUaW1lcG9pbnQpICsgCiAgICAgICAgZ2dwbG90Mjo6Z2VvbV9qaXR0ZXIod2lkdGggPSAwLjIsIGFscGhhID0gMC41LCBzaXplID0gMS41KSArIAogICAgICAgICMgbGlnaHQgZ3VpZGluZyBsaW5lIHJlcHJlc2VudGluZyAwIGV4cG9zdXJlCiAgICAgICAgZ2dwbG90Mjo6Z2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgc2l6ZSA9IDAuMTUpICsgCiAgICAgICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzb3J0KG5hbWVzKHBhbGV0dGUpKSkgKwogICAgICAgIGdncGxvdDI6OnN0YXRfc3VtbWFyeShjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjMpICsgCiAgICAgICAgZ2dwbG90Mjo6bGFicyh4ID0gIlR1bW9yIGRlc2NyaXB0b3IiLAogICAgICAgICAgICAgICAgICAgICAgeSA9ICJUTUIiKSArCiAgICAgICAgdGhlbWVfUHVibGljYXRpb24oKSArCiAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgeWxpbSkpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkpCgojIFNhdmUgdGhlIHBsb3QKZ2dzYXZlKGZpbGVuYW1lID0gIlRNQi11bnBhaXJlZC1sb25naXR1ZGluYWwtc2FtcGxlcy5wZGYiLAogICAgICAgcGF0aCA9IHBsb3RzX2RpciwgCiAgICAgICB3aWR0aCA9IDEwLCAKICAgICAgIGhlaWdodCA9IDUsIAogICAgICAgZGV2aWNlID0gInBkZiIsIAogICAgICAgdXNlRGluZ2JhdHMgPSBGQUxTRSkKYGBgCgoKIyBBbGwgdW5wYWlyZWQgc2FtcGxlcyBhY3Jvc3MgY2FuY2VyIHR5cGVzCldlIHdpbGwgdXNlIHRoZSBgc2hvcnRfaGlzdG9sb2d5YCBjb2x1bW4gdG8gZGlzcGxheSBUTUIgZGlmZmVyZW5jZXMgYWNyb3NzIGNhbmNlciB0eXBlcy4KCmBgYHtyIHBsb3QtY2FuY2VyLWdyb3VwLCBmaWcud2lkdGggPSAyNSwgZmlnLmhlaWdodCA9IDIwLCBmaWcuZnVsbHdpZHRoID0gVFJVRX0KcHJpbnQoZGZfcGxvdCAlPiUKICAgICAgICBnZ3Bsb3QyOjpnZ3Bsb3QoKSArIAogICAgICAgIGdncGxvdDI6OmFlcyh4ID0gdHVtb3JfZGVzY3JpcHRvciwgCiAgICAgICAgICAgICAgICAgICAgIHkgPSB0bWIsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gVGltZXBvaW50KSArIAogICAgICAgIGdncGxvdDI6Omdlb21faml0dGVyKHdpZHRoID0gMC4yLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDEuNSkgKyAKICAgICAgICAjIGxpZ2h0IGd1aWRpbmcgbGluZSByZXByZXNlbnRpbmcgMCBleHBvc3VyZQogICAgICAgIGdncGxvdDI6Omdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIHNpemUgPSAwLjE1KSArIAogICAgICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc29ydChuYW1lcyhwYWxldHRlKSkpICsKICAgICAgICBnZ3Bsb3QyOjpzdGF0X3N1bW1hcnkoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4zKSArIAogICAgICAgIGdncGxvdDI6OmZhY2V0X3dyYXAofnNob3J0X2hpc3RvbG9neSwgbnJvdyA9IDgpICsKICAgICAgICBnZ3Bsb3QyOjpsYWJzKHggPSAiVHVtb3IgZGVzY3JpcHRvciIsCiAgICAgICAgICAgICAgICAgICAgICB5ID0gIlRNQiIpICsKICAgICAgICB0aGVtZV9QdWJsaWNhdGlvbigpICsgCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsKICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCB5bGltKSkpCgojIFNhdmUgdGhlIHBsb3QKZ2dzYXZlKGZpbGVuYW1lID0gIlRNQi11bnBhaXJlZC1sb25naXR1ZGluYWwtc2FtcGxlcy1jYW5jZXItdHlwZS5wZGYiLCAKICAgICAgIHBhdGggPSBwbG90c19kaXIsIAogICAgICAgd2lkdGggPSAyNSwgCiAgICAgICBoZWlnaHQgPSAyMCwgCiAgICAgICBkZXZpY2UgPSAicGRmIiwgCiAgICAgICB1c2VEaW5nYmF0cyA9IEZBTFNFKQpgYGAKCldlIG9ic2VydmUgdGhhdCBtYWpvcml0eSBvZiBzYW1wbGVzIGFyZSBIaWdoLSBhbmQgTG93LWdyYWRlIGdsaW9tYXMgYXMgd2VsbCBhcyBFcGVuZHltb21hLCBzbyB3ZSB3aWxsIGNsYXNzaWZ5IGFjY29yZGluZ2x5ICh2ZXJzdXMgYW55IG90aGVyIGNhbmNlciB0eXBlcykuCgojIEFsbCB1bnBhaXJlZCBzYW1wbGVzIGFjcm9zcyBjYW5jZXIgdHlwZXMgc3VtbWFyaXplZAoKYGBge3IgcGxvdC1jYW5jZXItZ3JvdXAtc3VtLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDYsIGZpZy5mdWxsd2lkdGggPSBUUlVFfQoKCgoKc2hvcnRfaGlzdG9sb2d5X3N1bV9uIDwtIGRmX3Bsb3QgJT4lIAogIGNvdW50KHNob3J0X2hpc3RvbG9neV9zdW0pICU+JSAKICBkcGx5cjo6bXV0YXRlKHNob3J0X2hpc3RvbG9neV9zdW0gPSBnbHVlOjpnbHVlKCJ7c2hvcnRfaGlzdG9sb2d5X3N1bX0gKE49e259KSIpKQoKCiMgQ3JlYXRlIGNvbCB3aXRoIHNhbXBsZSBzaXplIHBlciBjYW5jZXIgdHlwZQpkZl9wbG90X24gPC0gZGZfcGxvdCAlPiUKICBkcGx5cjo6Y291bnQodHVtb3JfZGVzY3JpcHRvcikgJT4lCiAgZHBseXI6OmRpc3RpbmN0KCkgJT4lCiAgZHBseXI6OmlubmVyX2pvaW4oCiAgICBkcGx5cjo6c2VsZWN0KHBhbGV0dGVfZGYsIGRwbHlyOjpjb250YWlucygidHVtb3JfZGVzY3JpcHRvciIpKSkgJT4lCiAgZHBseXI6OnNlbGVjdCh0dW1vcl9kZXNjcmlwdG9yLCBuKSAlPiUKICAjIENyZWF0ZSB3cmFwcGVkIHdpdGggKG49WCkgZmFjdG9yIGNvbHVtbiBmb3IgY2FuY2VyIGdyb3VwcwogIGRwbHlyOjptdXRhdGUodHVtb3JfZGVzY3JpcHRvcl9uID0gZ2x1ZTo6Z2x1ZSgie3R1bW9yX2Rlc2NyaXB0b3J9IChOPXtufSkiKSkgJT4lCiAgZHBseXI6OmlubmVyX2pvaW4oZGZfcGxvdCkgJT4lCiAgdW5pcXVlKCkgJT4lCiAgIyByZXZlcnNlIG9yZGVyIGxldmVscyB0byBhbHBoYWJldGl6ZSB3aGVuIGZsaXBwaW5nIGNvb3JkaW5hdGVzCiAgbXV0YXRlKHR1bW9yX2Rlc2NyaXB0b3JfbiA9IGZjdF9yZXYodHVtb3JfZGVzY3JpcHRvcl9uKSkgCgpwcmludChkZl9wbG90ICU+JSAKICAgICAgICBnZ3Bsb3QyOjpnZ3Bsb3QoKSArIAogICAgICAgIGdncGxvdDI6OmFlcyh4ID0gdHVtb3JfZGVzY3JpcHRvciwgCiAgICAgICAgICAgICAgICAgICAgIHkgPSB0bWIsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gVGltZXBvaW50KSArIAogICAgICAgIGdncGxvdDI6Omdlb21faml0dGVyKHdpZHRoID0gMC4yLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDEuNSkgKyAKICAgICAgICAjIGxpZ2h0IGd1aWRpbmcgbGluZSByZXByZXNlbnRpbmcgMCBleHBvc3VyZQogICAgICAgIGdncGxvdDI6Omdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIHNpemUgPSAwLjE1KSArIAogICAgICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc29ydChuYW1lcyhwYWxldHRlKSkpICsKICAgICAgICBnZ3Bsb3QyOjpzdGF0X3N1bW1hcnkoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4zKSArIAogICAgICAgIGdncGxvdDI6OmZhY2V0X3dyYXAofnNob3J0X2hpc3RvbG9neV9zdW0sIG5yb3cgPSAxKSArCiAgICAgICAgZ2dwbG90Mjo6bGFicyh4ID0gIlR1bW9yIGRlc2NyaXB0b3IiLAogICAgICAgICAgICAgICAgICAgICAgeSA9ICJUTUIiKSArCiAgICAgICAgdGhlbWVfUHVibGljYXRpb24oKSArIAogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKSArCiAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgeWxpbSkpKQoKIyBTYXZlIHRoZSBwbG90Cmdnc2F2ZShmaWxlbmFtZSA9ICJUTUItdW5wYWlyZWQtbG9uZ2l0dWRpbmFsLXNhbXBsZXMtY2FuY2VyLXR5cGUtc3VtLnBkZiIsIAogICAgICAgcGF0aCA9IHBsb3RzX2RpciwgCiAgICAgICB3aWR0aCA9IDEyLCAKICAgICAgIGhlaWdodCA9IDYsIAogICAgICAgZGV2aWNlID0gInBkZiIsIAogICAgICAgdXNlRGluZ2JhdHMgPSBGQUxTRSkKYGBgCgojIFN1bW1hcnkgc3RhdGlzdGljcyBmb3IgVGltZXBvaW50cyBhbmQgY2FuY2VyIHR5cGVzCkNvbnNpZGVyaW5nIHRoZSBpbmVxdWFsaXRpZXMgaW4gdGhlIHNhbXBsaW5nIGVmZm9ydCBmb3IgZWFjaCB0aW1lcG9pbnQsIGxldCdzIGV4cGxvcmUgd2hldGhlciB0aGUgc2FtcGxpbmcgc2l6ZSBhZmZlY3RzIHRoZSBvYnNlcnZlZCBwYXR0ZXJucywgZS5nLiwgaW5kaWNhdGlvbiBvZiBQcm9ncmVzc2l2ZSBhbmQgUmVjdXJyZW5jZSBoYXZpbmcgaGlnZXIgVE1CIGNvbXBhcmVkIHRvIERpYWdub3NpcyBmb3IgSGlnaC1ncmFkZSBnbGlvbWEgcGF0aWVudHMuCgpgYGB7ciBzdW1tYXJ5LXN0YXRpc3RpY3MsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLmZ1bGx3aWR0aCA9IFRSVUV9CiMgSW5zcGVjdCBzb21lIHJhbmRvbSByb3dzIG9mIHRoZSBkYXRhIGJ5IGdyb3VwcwpzZXQuc2VlZCgyMDIzKQpkZl9wbG90ICU+JSAKICBzZWxlY3Qoc2hvcnRfaGlzdG9sb2d5X3N1bSwgdHVtb3JfZGVzY3JpcHRvciwgdG1iLCBsb2cxMF90bWIpICU+JSAKICBzYW1wbGVfbl9ieShzaG9ydF9oaXN0b2xvZ3lfc3VtLCB0dW1vcl9kZXNjcmlwdG9yLCB0bWIsIHNpemUgPSAxKQoKIyBDb21wdXRlIHNvbWUgc3VtbWFyeSBzdGF0aXN0aWNzIChtZWFuIGFuZCBzZCkgYnkgZ3JvdXBzOgpzdGF0LnN1bW1hcnkgPC0gZGZfcGxvdCAlPiUKICBncm91cF9ieShzaG9ydF9oaXN0b2xvZ3lfc3VtLCB0dW1vcl9kZXNjcmlwdG9yKSAlPiUKICBnZXRfc3VtbWFyeV9zdGF0cyh0bWIsIHR5cGUgPSAibWVhbl9zZCIpICU+JSAKICBmaWx0ZXIoIW4gPD0gMikgIyByZW1vdmUgaWYgdG90YWwgbnVtYmVyIG9mIHZhbHVlcyBwZXIgZ3JvdXAgaXMgbGVzcyB0aGFuIDIKc3RhdC5zdW1tYXJ5CgojIFBhaXJ3aXNlIGNvbXBhcmlzb25zIGJldHdlZW4gdGltZSBwb2ludHMgYXQgZWFjaCBncm91cCBsZXZlbHMKIyBQYWlyZWQgdC10ZXN0IGlzIHVzZWQgYmVjYXVzZSB3ZSBoYXZlIHJlcGVhdGVkIG1lYXN1cmVzIGJ5IHRpbWUKc3RhdC50ZXN0IDwtIGRmX3Bsb3QgJT4lCiAgZ3JvdXBfYnkoc2hvcnRfaGlzdG9sb2d5X3N1bSkgJT4lCiAgcGFpcndpc2VfdF90ZXN0KGxvZzEwX3RtYiB+IHR1bW9yX2Rlc2NyaXB0b3IsIAogICAgICAgICAgICAgICAgICBwYWlyZWQgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgIHAuYWRqdXN0Lm1ldGhvZCA9ICJib25mZXJyb25pIikKc3RhdC50ZXN0CgojIEFkZCBzdGF0aXN0aWNhbCB0ZXN0IHAtdmFsdWVzCnN0YXQudGVzdCA8LSBzdGF0LnRlc3QgJT4lIGFkZF94eV9wb3NpdGlvbih4ID0gInR1bW9yX2Rlc2NyaXB0b3IiKQoKIyBDcmVhdGUgYnhwCnByaW50KGdnYm94cGxvdChkZl9wbG90LAogICAgICAgICAgICAgICAgeCA9ICJ0dW1vcl9kZXNjcmlwdG9yIiwKICAgICAgICAgICAgICAgIHkgPSAibG9nMTBfdG1iIiwKICAgICAgICAgICAgICAgIGNvbG9yID0gInR1bW9yX2Rlc2NyaXB0b3IiLAogICAgICAgICAgICAgICAgcGFsZXR0ZSA9IHBhbGV0dGUpICsKICAgICAgICBmYWNldF93cmFwKH5zaG9ydF9oaXN0b2xvZ3lfc3VtLCBucm93ID0gMSkgKwogICAgICAgIHRoZW1lX1B1YmxpY2F0aW9uKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKwogICAgICAgIHN0YXRfcHZhbHVlX21hbnVhbChzdGF0LnRlc3QsIGxhYmVsID0gInAuYWRqLnNpZ25pZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXAuaW5jcmVhc2UgPSAwLjA4LCBoaWRlLm5zID0gVFJVRSwgdGlwLmxlbmd0aCA9IDApKQoKIyBTYXZlIHRoZSBwbG90Cmdnc2F2ZShmaWxlbmFtZSA9ICJUTUItQnhwLXN0YXQtdGVzdC5wZGYiLCAKICAgICAgIHBhdGggPSBwbG90c19kaXIsIAogICAgICAgd2lkdGggPSAxMiwgCiAgICAgICBoZWlnaHQgPSA2LCAKICAgICAgIGRldmljZSA9ICJwZGYiLCAKICAgICAgIHVzZURpbmdiYXRzID0gRkFMU0UpCgoKIyBDcmVhdGUgaml0dGVyIHBsb3QKcHJpbnQoZGZfcGxvdCAlPiUgCiAgICAgICAgZ2dwbG90Mjo6Z2dwbG90KCkgKyAKICAgICAgICBnZ3Bsb3QyOjphZXMoeCA9IHR1bW9yX2Rlc2NyaXB0b3IsIAogICAgICAgICAgICAgICAgICAgICB5ID0gbG9nMTBfdG1iLAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IFRpbWVwb2ludCkgKyAKICAgICAgICBnZ3Bsb3QyOjpnZW9tX2ppdHRlcih3aWR0aCA9IDAuMiwgYWxwaGEgPSAwLjUsIHNpemUgPSAxLjUpICsgCiAgICAgICAgIyBsaWdodCBndWlkaW5nIGxpbmUgcmVwcmVzZW50aW5nIDAgZXhwb3N1cmUKICAgICAgICBnZ3Bsb3QyOjpnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBzaXplID0gMC4xNSkgKwogICAgICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc29ydChuYW1lcyhwYWxldHRlKSkpICsKICAgICAgICBmYWNldF93cmFwKH5zaG9ydF9oaXN0b2xvZ3lfc3VtLCBucm93ID0gMSkgKwogICAgICAgIHRoZW1lX1B1YmxpY2F0aW9uKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKwogICAgICAgIHN0YXRfcHZhbHVlX21hbnVhbChzdGF0LnRlc3QsIGxhYmVsID0gInAuYWRqLnNpZ25pZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXAuaW5jcmVhc2UgPSAwLjA4LCBoaWRlLm5zID0gVFJVRSwgdGlwLmxlbmd0aCA9IDApKQoKIyBTYXZlIHRoZSBwbG90Cmdnc2F2ZShmaWxlbmFtZSA9ICJUTUItaml0dGVyLXN0YXQtdGVzdC5wZGYiLCAKICAgICAgIHBhdGggPSBwbG90c19kaXIsIAogICAgICAgd2lkdGggPSAxMiwgCiAgICAgICBoZWlnaHQgPSA2LCAKICAgICAgIGRldmljZSA9ICJwZGYiLCAKICAgICAgIHVzZURpbmdiYXRzID0gRkFMU0UpCgojIFRoaXMgY29kZSB3YXMgaW5zcGlyZWQgYnkgdGhlIGZvbGxvd2luZzoKIyBIT1cgVE8gUEVSRk9STSBNVUxUSVBMRSBQQUlSRUQgVC1URVNUUyBJTiBSCiMgaHR0cHM6Ly93d3cuZGF0YW5vdmlhLmNvbS9lbi9ibG9nL2hvdy10by1wZXJmb3JtLW11bHRpcGxlLXBhaXJlZC10LXRlc3RzLWluLXIvCmBgYAoKYGBge3IgZWNobz1UUlVFfQpzZXNzaW9uSW5mbygpCmBgYAo=